import gnu.io.SerialPort;
import gnu.io.UnsupportedCommOperationException;

import java.awt.Color;
import java.awt.FileDialog;
import java.awt.Font;
import java.awt.Frame;
import java.awt.Insets;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.util.Properties;
import java.util.Timer;
import java.util.TimerTask;

import javax.swing.ImageIcon;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JFileChooser;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPopupMenu;
import javax.swing.JTextArea;
import javax.swing.ProgressMonitor;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
import javax.swing.UIManager;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import javax.swing.text.Keymap;



public class SerialConsoleTextArea extends JTextArea implements MouseListener,PropertyChangeListener,propertyReadWritable {
	
	/**
	 * 
	 */
	private static final int CR	= 0x0d;
	private static final int LF	= 0x0a;
	
	private static final long serialVersionUID = 1L;
	public transient SerialPort CommPort = null;
	
	private transient JPopupMenu contextMenu = new JPopupMenu(); // �|�b�v�A�b�v���j���[�𐶐�
	private ProgressMonitor filtTransmitProgressMonitor=null;
	private transient TransmitFileTask fileTransmitTask=null;
	private String commParam = new String("");
	
	private int TxIntervalms = 0;		// tx interval in millisecond
	private int TxLineIntervalms = 100;	// tx line interval in millisecond
	private int	TxTermChar = 2; 		// 0:CR, 1:LF 2: 3:CR+LF
	private int RxTermChar = 0; 		// 0:CR, 1:LF 2: 3:CR+LF
	private boolean LocalEcho = false;	// 
	private int maxBufferSize = 30000;	// ��M�o�b�t�@�o�C�g��
	private String loggFileName = new String();
	private BufferedOutputStreamWithDeletable outLogBuffer=null; 
	private int loggEnable = 0;
	private JCheckBoxMenuItem checkBoxLoggEnable = null;
	private Timer rxTimer = null;
	private PipedOutputStream outStream = null;
	private int colorSet = 0;
	private Font font = null;
	public boolean OutBinaryMode = false;
	public boolean DispBinaryMode = false;
	public boolean DisplayOff = false;
	//private SerialConsolePropertyDialog propDialog = null;
	public long TxCounter=0L;
	public long RxCounter=0L;
	private ConsoleDialog Parent=null;
	
	/**
	 * �e ConsoleDialog���Z�b�g
	 * @param p
	 */
	public void setParent(ConsoleDialog p){
		Parent = p;
	}
	
	/**
	 *  ���O�t�@�C�������擾
	 * @return
	 */
	public String getLoggFileName() {
		return loggFileName;
	}

	/**
	 *  ���O�t�@�C�������Z�b�g
	 * @param loggFileName
	 */
	public void setLoggFileName(String loggFileName) {
		if(loggFileName==null){
			doLoggFileChoose();
		}
		else{
			this.loggFileName = loggFileName;
			if(getLoggEnable()!=0){
				setLoggEnable(0);
				setLoggEnable(1);
			}
		}
	}
	/**
	 *  ���O�t�@�C�������ݏ�Ԃ�Ԃ�
	 * @return
	 */
	public int getLoggEnable() {
		return loggEnable;
	}
	/**
	 *  ���O�t�@�C�������ݏ�Ԃ��Z�b�g
	 * @param loggEnable
	 */
	public void setLoggEnable(int loggEnable) {
		this.loggEnable = loggEnable;
		if(loggEnable==0) setLoggEnable(false);
		else 			  setLoggEnable(true);
		
	}
	
	/**
	 *  ���M�L�����N�^�C���^�[�o�� ms�P��
	 * @return
	 */
	public int getTxIntervalms() {
		return TxIntervalms;
	}

	/**
	 *  ���M�L�����N�^�C���^�[�o�� ms�P��
	 * @return
	 */
	public void setTxIntervalms(int txIntervalms) {
		TxIntervalms = txIntervalms;
	}

	/**
	 *  ���M���C���C���^�[�o���@ms�P��
	 * @return
	 */
	public int getTxLineIntervalms() {
		return TxLineIntervalms;
	}

	/**
	 *  ���M���C���C���^�[�o�� ms�P��
	 * @return
	 */
	public void setTxLineIntervalms(int txLineIntervalms) {
		TxLineIntervalms = txLineIntervalms;
	}

	/**
	 * ���M��s�R�[�h
	 * 0:CR, 1:LF 2: 3:CR+LF
	 * @return
	 */
	public int getTxTermChar() {
		return TxTermChar;
	}

	/**
	 * ���M��s�R�[�h
	 * 0:CR, 1:LF 2: 3:CR+LF
	 * @return
	 */
	public void setTxTermChar(int txTermChar) {
		TxTermChar = txTermChar;
	}

	/**
	 * ��M��s�R�[�h
	 * 0:CR, 1:LF 2: 3:CR+LF
	 * @return
	 */
	public int getRxTermChar() {
		return RxTermChar;
	}

	/**
	 * ��M��s�R�[�h
	 * 0:CR, 1:LF 2: 3:CR+LF
	 * @return
	 */
	public void setRxTermChar(int rxTermChar) {
		RxTermChar = rxTermChar;
	}

	/**
	 * ���[�J���G�R�[ �L��H
	 * @return
	 */
	public boolean isLocalEcho() {
		return LocalEcho;
	}

	/**
	 * ���[�J���G�R�[ �L��H
	 * @return
	 */
	public void setLocalEcho(boolean localEcho) {
		LocalEcho = localEcho;
		/////////////////////////////////////////////
	}
	/**
	 * COM�p�����[�^�𕶎���ŕԂ� �@COM1/9600/8/1/0/0
  	 *  COM�|�[�g/BPS/CharLength/StopBit(1,2,3(1.5),/Parity(0(none),1(odd),(even)/Flow 0(none),1(XON/XOFF),2(RTS/CTS)
	 * @return
	 */
	public String getCommParam(){
		return commParam;
	}
	
	public void setCommParam(String param){
		if(param==null) return;
		if(commParam.compareTo(param)!=0){
			commParam = param;
		}
		
	}
	/////////////////////////////////////////////
	// �R���X�g���N�^
	public SerialConsoleTextArea(){
		super();
		loggFileName=System.getProperty("user.home"); // ���[�U�̃z�[���f�B���N�g�����N�_�ɂ��Ă���
		setFocusable(true); //�@�t�H�[�J�X���󂯎��
		setEditable(true); //�@�L�����b�g��\�����邽�߂� 
		Insets m = getMargin();
		m.top += 5;
		m.left += 5;
		m.right += 5;
		m.bottom += 5;
		setMargin(m);
		addKeyListener(new KeyListener (){
			@Override
			public void keyPressed(KeyEvent arg0) {
				if(!LocalEcho) setEditable(false); // ���^�[���L�[�̉�s�𖳎����邽��
			}

			@Override
			public void keyReleased(KeyEvent arg0) {
				setEditable(true);// ���^�[���L�[�̉�s�𖳎����邽��
			}

			@Override
			public void keyTyped(KeyEvent arg0) {
				whenKeyTyped(arg0);
			}
			
		});
		addMouseListener(this); // �}�E�X���X�i��o�^
		
		setComponentPopupMenu(contextMenu);	// ��������Ȃ��Ƃ��̃R���|�[�l���g�̎q�ɂȂ�Ȃ��悤��
		// ���ׂĂ�I��
		addPopupMenuItem(contextMenu,"Select all ALT+A", new ActionListener(){ 
			@Override
			public void actionPerformed(ActionEvent arg0) {
				selectAll();
			}
	       });
		// �Z�p���[�^
		contextMenu.addSeparator();
		// �R�s�[
		addPopupMenuItem(contextMenu,"Copy      ALT+C","images/copy.gif", new ActionListener(){
			@Override
			public void actionPerformed(ActionEvent arg0) {
				copy();
			}
	       });
		// �Z�p���[�^
		contextMenu.addSeparator();
		// �y�[�X�g����
		addPopupMenuItem(contextMenu,"Paste     ALT+V","images/action_paste.gif", new ActionListener(){ 
			@Override
			public void actionPerformed(ActionEvent arg0) {
				onPaste();
			}
			});
		// �Z�p���[�^
		contextMenu.addSeparator();
		//�@COM�p�����[�^
		addPopupMenuItem(contextMenu,"COM Setting","images/cog_edit.png", new ActionListener(){ 
			@Override
			public void actionPerformed(ActionEvent arg0) {
				setParamFromDialog();
			}
		});
		addPopupMenuItem(contextMenu,"Terminal Setting","images/cog_edit.png", new ActionListener(){ 
			@Override
			public void actionPerformed(ActionEvent arg0) {
				doTerminalSettingDialog();
			}
		});

		// �Z�p���[�^
		contextMenu.addSeparator();
		//�@�N���A
		addPopupMenuItem(contextMenu,"Clear contents","images/page_white_star.png", new ActionListener(){ 
			@Override
			public void actionPerformed(ActionEvent arg0) {
				resetContents();
			}
			});
		// �Z�p���[�^
		contextMenu.addSeparator();
		// �t�@�C�����瑗�M
		addPopupMenuItem(contextMenu,"Transmit file","images/package_go.png", new ActionListener(){ 
			@Override
			public void actionPerformed(ActionEvent arg0) {
				transmitFromFile();
			}
		});
		// �Z�p���[�^
		contextMenu.addSeparator();
		
		JMenu  contextMenuColorParent = new JMenu("Set Color");
		contextMenuColorParent.setIcon(new ImageIcon(getClass().getClassLoader().getResource("images/color.png")));
		JMenuItem contextMenuColor = new JMenuItem();
		//��ʂ̐F��������
		addPopupMenuItem(contextMenuColorParent,"white background","images/ConsoleWhite.png", new ActionListener(){ 
			@Override
			public void actionPerformed(ActionEvent arg0) {
				setColor(0);
			}
		});
		addPopupMenuItem(contextMenuColorParent,"black background","images/ConsoleBlack.png", new ActionListener(){ 
			@Override
			public void actionPerformed(ActionEvent arg0) {
				setColor(1);
			}
		});
		addPopupMenuItem(contextMenuColorParent,"green text","images/ConsoleBlackGreen.png", new ActionListener(){ 
			@Override
			public void actionPerformed(ActionEvent arg0) {
				setColor(2);
			}
		});
		contextMenu.add(contextMenuColorParent);
		// �Z�p���[�^
		contextMenu.addSeparator();
		// �t�H���g�I��
		addPopupMenuItem(contextMenu,"Font","images/text_uppercase.png", new ActionListener(){ 
			@Override
			public void actionPerformed(ActionEvent arg0) {
				setFontFromDialog();
			}
		});
		// �Z�p���[�^
		contextMenu.addSeparator();
		// ���O�t�@�C���I��
		addPopupMenuItem(contextMenu,"Log file...","images/database_gear.png", new ActionListener(){ 
			@Override
			public void actionPerformed(ActionEvent arg0) {
				doLoggFileChoose();
			}
		});
		// ���O���Ƃ邩�ǂ���
		checkBoxLoggEnable = addPopupCheckBoxMenuItem(contextMenu,"Log","images/database.png", new ActionListener(){ 
			@Override
			public void actionPerformed(ActionEvent arg0) {
				JCheckBoxMenuItem logmenu = (JCheckBoxMenuItem)arg0.getSource();
				if(loggEnable==0){
					setLoggEnable(true);
				}
				else{
					setLoggEnable(false);
				}
			}
		});
		
	
	}
	private void onPaste(){
		Clipboard clipboard = getToolkit().
        getSystemClipboard();
		Transferable data = clipboard.getContents(this);
		if (data != null && data.isDataFlavorSupported(DataFlavor.stringFlavor)){
			try{
				String pm = (String)data.getTransferData(DataFlavor.stringFlavor);
				outputChar(pm);
			}
			catch(Exception e) {
			}
		}
	}
	////////////////////////////////////////////////////////
	// �^�[�~�i���Z�b�e�B���O��I�ԃ_�C�A���O�����s����
	public void doTerminalSettingDialog(){
		SerialConsolePropertyDialog propDialog = new SerialConsolePropertyDialog(null);
		propDialog.getJContentPane().txTerminateChar = TxTermChar;
		propDialog.getJContentPane().rxTerminateChar = RxTermChar;
		propDialog.getJContentPane().txCharInterval = TxIntervalms;
		propDialog.getJContentPane().txLineInterval = TxLineIntervalms;
		propDialog.getJContentPane().localEcho = LocalEcho;		
		propDialog.getJContentPane().UpdateData(true);
		propDialog.setLocationRelativeTo(this);
		propDialog.setVisible(true);
		if(propDialog.ResultOK){
			TxTermChar = propDialog.getJContentPane().txTerminateChar;
			RxTermChar = propDialog.getJContentPane().rxTerminateChar;
			TxIntervalms = propDialog.getJContentPane().txCharInterval;
			TxLineIntervalms = propDialog.getJContentPane().txLineInterval;
			LocalEcho = propDialog.getJContentPane().localEcho;
		
		}
		return;
	}
	////////////////////////////////////////////////////////
	// ���O�t�@�C����I�ԃ_�C�A���O�����s����
	private void doLoggFileChoose(){
		JFileChooser fl_dlg = new JFileChooser();
		fl_dlg.setFileSelectionMode(JFileChooser.FILES_ONLY);
		File f = new File(loggFileName);
		fl_dlg.setCurrentDirectory(f);
		if(f.isFile()) {
			fl_dlg.setSelectedFile(f); // �ŏ��Ƀt�@�C����I����Ԃɂ���
		}
		if(JFileChooser.APPROVE_OPTION == fl_dlg.showSaveDialog(null)){
			File file = fl_dlg.getSelectedFile();
			loggFileName = file.getAbsolutePath();
		}
	}
	////////////////////////////////////////////////////////
	// ���O�����E�֎~����
	private void setLoggEnable(boolean enable){
		if(enable){
			if(loggEnable == 0){
				FileOutputStream outFile;
				try {
					outFile = new FileOutputStream(loggFileName);
					outLogBuffer = new BufferedOutputStreamWithDeletable(outFile);
					loggEnable = 1;
					checkBoxLoggEnable.setState(true);
				} catch (FileNotFoundException e) {
					JOptionPane.showMessageDialog(null, "Fail to open logg file:\n"+loggFileName);
				}
			}
		}
		else{
			if(outLogBuffer!=null){
				try {
					outLogBuffer.flush();
					outLogBuffer.close();
					loggEnable = 0;
				} catch (IOException e) {
					JOptionPane.showMessageDialog(null, "Fail to close logg file:\n"+loggFileName);
				}
			}
			loggEnable = 0;
			checkBoxLoggEnable.setState(false);
		}
	}
	////////////////////////////////////////////////////////
	//���j���[��add����⏕�֐�
	private JMenuItem addPopupMenuItem(JPopupMenu pum,String name, String imageFile,ActionListener al) {
		JMenuItem item = new JMenuItem(name);
		item.setIcon(new ImageIcon(getClass().getClassLoader().getResource(imageFile)));
		item.addActionListener(al);
		pum.add(item);
		return item;
	}
	////////////////////////////////////////////////////////
	//���j���[��add����⏕�֐�
	private JMenuItem addPopupMenuItem(JPopupMenu pum,String name, ActionListener al) {
		JMenuItem item = new JMenuItem(name);
		item.addActionListener(al);
		pum.add(item);
		return item;
	}
	////////////////////////////////////////////////////////
	//���j���[��add����⏕�֐�
	private JCheckBoxMenuItem addPopupCheckBoxMenuItem(JPopupMenu pum,String name, ActionListener al) {
		JCheckBoxMenuItem item = new JCheckBoxMenuItem(name);
		item.addActionListener(al);
		pum.add(item);
		return item;
	}
	////////////////////////////////////////////////////////
	//���j���[��add����⏕�֐�
	private JCheckBoxMenuItem addPopupCheckBoxMenuItem(JPopupMenu pum,String name,String imageFile, ActionListener al) {
		JCheckBoxMenuItem item = new JCheckBoxMenuItem(name);
		item.setIcon(new ImageIcon(getClass().getClassLoader().getResource(imageFile)));
		item.addActionListener(al);
		pum.add(item);
		return item;
	}
	////////////////////////////////////////////////////////
	//���j���[��add����⏕�֐�
	private JMenuItem addPopupMenuItem(JMenu pum,String name, ActionListener al) {
		JMenuItem item = new JMenuItem(name);
		item.addActionListener(al);
		pum.add(item);
		return item;
	}
	////////////////////////////////////////////////////////
	//���j���[��add����⏕�֐�
	private JMenuItem addPopupMenuItem(JMenu pum,String name, String imageFile,ActionListener al) {
		JMenuItem item = new JMenuItem(name);
		item.setIcon(new ImageIcon(getClass().getClassLoader().getResource(imageFile)));
		item.addActionListener(al);
		pum.add(item);
		return item;
	}
	////////////////////////////////////////////////////////
	// �t�@�C�����瑗�M
	private void transmitFromFile(){
		JFileChooser filechooser = new JFileChooser();
		int selected = filechooser.showOpenDialog(this);
		if(selected != JFileChooser.APPROVE_OPTION) return;
		File file = filechooser.getSelectedFile();
		try {
			FileInputStream fi = new FileInputStream(file);
			int max = (int)file.length();
			
			filtTransmitProgressMonitor = new ProgressMonitor(this, String.format("%s",file.getName()), "note", 0, max);

			fileTransmitTask = new TransmitFileTask();
			fileTransmitTask.fileinput = fi;
			fileTransmitTask.pm = filtTransmitProgressMonitor;
			//fileTransmitTask.addPropertyChangeListener(this);
			fileTransmitTask.execute();			
	        
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} 
		return;
	}
	//-------------------------------------------------------------
	// �t�@�C�����瑗�M�̕ʃX���b�h�ɂ����s
	class TransmitFileTask extends SwingWorker<Void, Void> {
		public FileInputStream fileinput=null;
		public ProgressMonitor pm = null;
		private void sleepms(int ms){
			if(ms<=0) return;
			long t1 = System.currentTimeMillis();
			while(System.currentTimeMillis()-t1 < ms){
			}
			return;
		}
		private boolean isTermChar(byte c){
			boolean ret = false;
			switch(RxTermChar){// 0:CR, 1:LF 2: 3:CR+LF
			case 0:
				if(c == CR) ret=true;
				break;
			case 1:
			case 2:
				if(c==LF) ret = true;
				break;
			}
			return ret;
		}
		@Override
		protected Void doInBackground() throws Exception {
			int rdcount=0;
			int rd;
			int max = pm.getMaximum();
			int min = pm.getMinimum();
			int factor = 1;
			while((rd = fileinput.read()) != -1){
				outputChar((byte)rd);
				if(isTermChar((byte)rd)) sleepms(TxLineIntervalms*factor);
				else	 				 sleepms(TxIntervalms*factor);
				if(factor>1) factor--;
				rdcount++;
				pm.setNote(String.format("%4.1f%%  %d/%d",100*(float)(rdcount-min)/(float)(max-min),rdcount,max));
				pm.setProgress(rdcount); //�v���O���X�o�[�Ɍ��ݒl���Z�b�g
				if(pm.isCanceled()) break;
			}
			fileinput.close();
			return null;
		}
		 
	}    
	
	//////////////////////////////////
	// �L�[�������ꂽ�Ƃ�����
	private void whenKeyTyped(KeyEvent arg0){
		byte outc = (byte)arg0.getKeyChar();
		if(CommPort==null) return;
		// Ctrl+c Ctrl+v
		int keymody = arg0.getModifiers();
		if(keymody==KeyEvent.ALT_MASK){
			char keycode = arg0.getKeyChar();
			if(keycode=='c' || keycode=='C'){
				copy();
				setSelectionStart(getSelectionEnd());
			}
			else if(keycode=='v' || keycode=='V'){
				onPaste();
			}
			return;
		}
		outputChar(outc);
	}
	//////////////////////////////////
	//  COM�|�[�g�ւ̑��M
	public void outputChar(byte[] outs){
		for(int i=0;i<outs.length;i++){
			outputChar(outs[i]);
		}
		
	}
	public void outputChar(char[] outs){
		for(int i=0;i<outs.length;i++){
			outputChar((byte)outs[i]);
		}
		
	}
	public void outputChar(String outs){
		char[] ca = outs.toCharArray();
		outputChar(ca);
	}
	public void outputChar(byte outc){
		if(CommPort==null) return;
		try {
			OutputStream o = CommPort.getOutputStream();
			if(outc == '\n'){
				switch(TxTermChar){
				case 0: // CR
					if(outc == CR){
						outc = LF;
					}
					break;
				case 1: // LF
					break; //�������Ȃ�
				default: // CR+LF
					o.write(CR);
					TxCounter++;
					Thread.sleep(TxIntervalms);
				}
			}
			o.write(outc);
			TxCounter++;
			if(Parent!=null) Parent.onStatusChange();
			Thread.sleep(TxIntervalms);
			if(outc=='\n'){
				Thread.sleep(TxLineIntervalms);
			}
		} catch (IOException e) {
			e.printStackTrace();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		
	}
	
	////////////////////////////////////////////////////////
	// COM�|�[�g����̎�M
	public PipedInputStream getPipedInputStream(){
		//if(outStream != null) return null;
		outStream = new PipedOutputStream();
		PipedInputStream in = null;
		try {
			in = new PipedInputStream(outStream);
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		return in;
	}
	////////////////////////////////////////////////////////
	// COM�|�[�g����̎�M�I��
	public void closeInputStream(){
		DispBinaryMode = false;
		outStream = null;
	}
	////////////////////////////////////////////////////////
	// �V���A���ݒ�_�C�A���O
	private String doCommDialog(String param){
		SerialCommSettingDialog dlg = new SerialCommSettingDialog(null);
		dlg.setCommParam(param);
		dlg.setLocationRelativeTo(this);
		dlg.setVisible(true);
		if(dlg.exitCode != 1) return null;
		return dlg.getCommParam();
		
	}
	//////////////////////////////////
	// �ڑ���
	public boolean connect(){
		if(commParam.isEmpty()){
			if(!setParamFromDialog()) return false;
		}
		try {
			CommPort = (new SerialComm()).connect(100,commParam);
			rxTimer = new Timer();
			rxTimer.schedule(new ConsoleTimerTask(this),0,20);;
		
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		} catch (UnsatisfiedLinkError e) {
			return false;
		}
		//if(checkBoxConnect!=null) checkBoxConnect.setSelected(true);
		return true;
	}
	//////////////////////////////////
	// �ؒf��
	public void disconnect(){
		DispBinaryMode = false;
		if(CommPort!=null){
			CommPort.close();
			CommPort=null;
			rxTimer.cancel();
			rxTimer = null;
	//		if(checkBoxConnect!=null) checkBoxConnect.setSelected(false);
		}
	}
	public boolean isConnect(){
		if(CommPort==null) return false;
		return true;
	}
	
	public boolean setParamFromDialog(){
		String param = new String(commParam);
		if(null == (param = doCommDialog(param))) return false;
		commParam=param;
		if(CommPort!=null){
			disconnect();
			connect();
		}
		return true;
	}
	/////////////////////////////////////////////////
	// ��ʂ̃t�H���g��ύX����
	public void setFontFromDialog(){
		font=JFontDialog.chooseFont(this);
		setFont(font);
		
	}
	/////////////////////////////////////////////////
	// ��ʂ̐F��ύX����
	public void setColor(int code){
		int colback = 0xff << 24 | 0xff << 16 | 0xff << 8 | 0xff << 0;
		int colfore = 0xff << 24 | 0x00 << 16 | 0x00 << 8 | 0x00 << 0;
		colorSet =code;
		switch(code){
		case 1:	// black
			colback = 0xff << 24 | 0x00 << 16 | 0x00 << 8 | 0x00 << 0;
			colfore = 0xff << 24 | 0xff << 16 | 0xff << 8 | 0xff << 0;
			break;
		case 2:	// black (green char)
			colback = 0xff << 24 | 0x00 << 16 | 0x00 << 8 | 0x00 << 0;
			colfore = 0xff << 24 | 150 << 16 | 210 << 8 | 150 << 0;
			break;
		case 0:		// white
		default:
			colback = 0xff << 24 | 0xff << 16 | 0xff << 8 | 0xff << 0;
			colfore = 0xff << 24 | 0x00 << 16 | 0x00 << 8 | 0x00 << 0;
			break;
		}
		Color c = new Color(colback);
		setBackground(c);
		c = new Color(colfore);
		setForeground(c);
		
	}
	public int getColorSet(){
		return colorSet;
	}
	//////////////////////////////////////////////////////////////////////////////////////////////////////
	// �����Ԃ�K���Ȓ[��
	// �^�C�}�[���[�`���Ŏ�M���|�[�����O����
	class ConsoleTimerTask extends TimerTask {
		byte[] buffer = null;
		int index;
		int counter;
		boolean carret;
		SerialConsoleTextArea  textArea=null;
		Document doc ;
		
		ConsoleTimerTask(SerialConsoleTextArea ta){
			buffer = new byte[maxBufferSize];
			index=0;
			counter=0;
			carret=false;
			textArea = ta;
			doc = textArea.getDocument();
		}
		/////////////////////////////////////////////
		// �擪num�o�C�g���폜����B
		private void deleteTopByte(int num){
			try {
				doc.remove(0,100);
			} catch (BadLocationException e) {
				e.printStackTrace();
			}
		}
		/////////////////////////////////////////////
		// �ŏI�L�����N�^�������[�u����
		private void delLastChar(){
			int start = doc.getLength()-1;
			String s;
			try {
				s = doc.getText(start, 1);
				if(s.endsWith("\n")) return;
				doc.remove(start,1);
				if(loggEnable>0){
					outLogBuffer.deleteLastByte(1);
				}

			} catch (BadLocationException e1) {
				e1.printStackTrace();
			}
		}
		/////////////////////////////////////////////
		// �L�����N�^��ǉ�����
		private int AsciiChar = 0;
		private int NotAsciiChar = 0;
		private void addChar(byte[] cc){
			for(int i=0;i<cc.length;i++){
				if(cc[i]<=0) NotAsciiChar++;
				else AsciiChar++;
				if(AsciiChar+NotAsciiChar > 10){
					float ratio = AsciiChar/(float)(AsciiChar+NotAsciiChar);
					if(ratio < 0.7) DispBinaryMode=true;
				}
			}
			doc = textArea.getDocument();
			String s;
			try {
				s = new String(cc,"UTF-8");
				byte[] buf = s.getBytes();
				byte[] des = new byte[buf.length];
				int j=0;
				for(int i=0;i<buf.length;i++){
					if(!DisplayOff){
						if(DispBinaryMode){
							j++;
							// �����Ȃ�
						}
						else{
							switch(buf[i]){
							case CR:
							case LF:
								switch(RxTermChar){ // 0:CR, 1:LF 2: 3:CR+LF
								case 0: 
									if(buf[i]==CR) des[j++]='\n'; // CR=>LF�ɓǂݑւ���
									break;
								case 1:
									break;  // �Ȃɂ����Ȃ�
								default: // 2 CR+LF
									if(buf[i]!=CR) des[j++]='\n';	//�@CR�𖳎�����@�����R�[�h�̒���CR������Ƃ܂�������
									
								}
								break;
							case 0x08:	// BS
								if(j>0){				// ���o�b�t�@�̐擪�܂�
									if( des[j]!='\n'){	//�@���o�b�t�@�̉�s�܂� 
										j--;
										des[j++]=buf[i];
									}
								}
								else{					// �ߋ��̕������������߂�
									delLastChar();
									//del++;
								}
								break;
							case 0x07:	// Beep
								java.awt.Toolkit.getDefaultToolkit().beep(); 
								break;
							case 0x011: // ^Q xon
							case 0x013:	// ^S xoff
								break;
							default:
								des[j++]=buf[i];
							}
							
						}
					}
					else{
						des[j++]=buf[i];
					}
				}
				// ���o�b�t�@�𕶎���ɂ���
				if(j>0){
					byte[] des2 = new byte[j];
					System.arraycopy(des, 0, des2, 0, j);
					s = new String(des2,"UTF-8");
					if(!DisplayOff){
						if( des2[0] != 0x08) 	doc.insertString(doc.getLength(),s, null);
						if(loggEnable>0){
							try {
								//outLogBuffer.write(des2);
								outLogBuffer.write(s.getBytes());
							} catch (IOException e) {
								e.printStackTrace();
							}
						}
					}
					// �o�͂�����Ώo�͂���
					if(outStream != null){
						if(OutBinaryMode)		outStream.write(cc);
						else 				outStream.write(s.getBytes());
						outStream.flush();
					}
				}
			} catch (UnsupportedEncodingException e1) {
				e1.printStackTrace();
			} catch (BadLocationException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		///////////////////////////////////////////////////////////////////////////
		//�@��M�@���s�X���b�h 
		public void run(){
			if(textArea.CommPort==null) return;
			InputStream is;
			int len;
			try {
				is = textArea.CommPort.getInputStream();
				len = is.available();
				if(len<=0) return;
				byte[] cc = new byte[len];
				RxCounter+=len;
				if(Parent!=null) Parent.onStatusChange();
				is.read(cc);
				addChar(cc);
			} catch (IOException e) {
				e.printStackTrace();
			}
			// �Ō�ɃX�N���[�����Ă���
			textArea.setCaretPosition(textArea.getDocument().getLength());
		}
	}

	///////////////////////////
	// �}�E�X�N���b�N�� 
	@Override
	public void mouseClicked(MouseEvent e) {
		if (javax.swing.SwingUtilities.isRightMouseButton(e)) {
			// �E�N���b�N���̏���
			// �|�b�v�A�b�v���j���[��\��
			contextMenu.setFocusable(true);
			contextMenu.setLocation(e.getLocationOnScreen());
//			if(checkBoxConnect!=null){
//				checkBoxConnect.setSelected(isConnect());
//			}
			contextMenu.setVisible(true);
		} else if (javax.swing.SwingUtilities.isMiddleMouseButton(e)) {
			// ���{�^���N���b�N���̏���
		} else if (javax.swing.SwingUtilities.isLeftMouseButton(e)) {
			// ���N���b�N���̏���
		}
	}
	@Override
	public void mouseEntered(MouseEvent arg0) {
		
	}
	@Override
	public void mouseExited(MouseEvent arg0) {
		
	}
	@Override
	public void mousePressed(MouseEvent arg0) {
		
	}
	@Override
	public void mouseReleased(MouseEvent arg0) {
		
	}
	///////////////////////////
	// �t�@�C�����M�^�X�N�̐i���_�C�A���O����̃��b�Z�[�W
	@Override
	public void propertyChange(PropertyChangeEvent evt) {
		// �t�@�C�����M�^�X�N��progressDialog����
		if ("progress" == evt.getPropertyName()) {
			int progress = (Integer) evt.getNewValue();
			filtTransmitProgressMonitor.setProgress(progress);
			String message = String.format("Completed %d%%.\n", progress);
			filtTransmitProgressMonitor.setNote(message);
			if (filtTransmitProgressMonitor.isCanceled() || fileTransmitTask.isDone()) {
				if (filtTransmitProgressMonitor.isCanceled()) {
					fileTransmitTask.cancel(true);
				}
			}
		}
	}
	///////////////////////////
	// �v���p�e�B�����[�h
	@Override
	public void readProperty(Properties prop) {
		if(prop==null) return ;
		try{
			String cp = prop.getProperty("SERIAL-CONSOLE/COMMPARAM","COM1/9600/8/1/0/0");
			setCommParam(cp);
			TxIntervalms 		= Integer.valueOf(prop.getProperty("SERIAL-CONSOLE/TXINTERVAL_MS","0"));
			TxLineIntervalms 	= Integer.valueOf(prop.getProperty("SERIAL-CONSOLE/TXINTERVALLINE_MS","0"));
			TxTermChar 			= Integer.valueOf(prop.getProperty("SERIAL-CONSOLE/TXTERM_CHAR","0"));
			RxTermChar 			= Integer.valueOf(prop.getProperty("SERIAL-CONSOLE/RXTERM_CHAR","0"));
			LocalEcho 			=  prop.getProperty("SERIAL-CONSOLE/LOCALECHO","false").compareTo("true")==0;
			maxBufferSize		= Integer.valueOf(prop.getProperty("SERIAL-CONSOLE/MAXBUFFER","30000"));
			int col;
			Color color;
			col 				= Integer.valueOf(prop.getProperty("SERIAL-CONSOLE/COLOR/BACKGROUND","ffffffff"),16);
			color = new Color(col);
			setBackground(color);
			col 				= Integer.valueOf(prop.getProperty("SERIAL-CONSOLE/COLOR/FOREGROUND","ff000000"),16);
			color = new Color(col);
			setForeground(color);
	
			int fontsize 		= Integer.valueOf(prop.getProperty("SERIAL-CONSOLE/FONT/SIZE","12"));
			int fontstyle 		= Integer.valueOf(prop.getProperty("SERIAL-CONSOLE/FONT/STYLE","0"));
			String fontname     = prop.getProperty("SERIAL-CONSOLE/FONT/NAME","DIALOG");
			Font fon = new Font(fontname,fontstyle,fontsize);
			setFont(fon);
			
			String log = prop.getProperty("SERIAL-CONSOLE/LOG/NAME");
			if(log!=null) loggFileName = log; 
			
		}catch(NumberFormatException e){
			TxIntervalms = 0;
			TxLineIntervalms = 0;
			TxTermChar = 0;
			RxTermChar = 0;
			LocalEcho = false;
		}
	}
	///////////////////////////
	// Color�v���p�e�B�����C�g����⏕
	private void writePropertyColor(Properties prop,String section,Color col){
		int cols = col.getRGB();
		prop.setProperty(section, Integer.toString(cols,16));
	}
	///////////////////////////
	// �v���p�e�B�����C�g
	@Override
	public void writeProperty(Properties prop) {
		if(prop==null) return ;
		if(commParam == null) return;
		if(commParam.isEmpty()) return;
		prop.setProperty("SERIAL-CONSOLE/COMMPARAM", commParam);
		prop.setProperty("SERIAL-CONSOLE/TXINTERVAL_MS", String.valueOf(TxIntervalms));
		prop.setProperty("SERIAL-CONSOLE/TXINTERVALLINE_MS", String.valueOf(TxLineIntervalms));
		prop.setProperty("SERIAL-CONSOLE/TXTERM_CHAR", String.valueOf(TxTermChar));
		prop.setProperty("SERIAL-CONSOLE/RXTERM_CHAR", String.valueOf(RxTermChar));
		prop.setProperty("SERIAL-CONSOLE/LOCALECHO", String.valueOf(LocalEcho));
		prop.setProperty("SERIAL-CONSOLE/MAXBUFFER", String.valueOf(maxBufferSize));
		
		Color col = getBackground();
		writePropertyColor(prop,"SERIAL-CONSOLE/COLOR/BACKGROUND",col);
		col = getForeground();
		writePropertyColor(prop,"SERIAL-CONSOLE/COLOR/FOREGROUND",col);
		
		Font fnt = getFont();
		prop.setProperty("SERIAL-CONSOLE/FONT/SIZE", String.valueOf(fnt.getSize()));
		prop.setProperty("SERIAL-CONSOLE/FONT/STYLE", String.valueOf(fnt.getStyle()));
		prop.setProperty("SERIAL-CONSOLE/FONT/NAME", fnt.getName());
		
		prop.setProperty("SERIAL-CONSOLE/LOG/NAME", loggFileName);
		
		
	}
	//////////////////////////////////////////////////////
	// ���e���N���A
	public void resetContents(){
		Document doc = getDocument();
		try {
			doc.remove(0,doc.getLength());
		} catch (BadLocationException e) {
			e.printStackTrace();
		}
	}

}
